import { fileURLToPath, URL } from "node:url";
import fs from "fs";
import path from "path";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// 自动导入组件库组件的插件
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import { createStyleImportPlugin, ElementPlusResolve } from "vite-plugin-style-import";
// 安装vite-plugin-vue-setup-extend插件让<script setup>标签</script>可以直接自定义组件名
import VitePluginVueSetupExtend from "vite-plugin-vue-setup-extend";
// 静态资源压缩插件
import ViteCompression from "vite-plugin-compression";
// autoprefixer是一个后处理器，它使用Can I Use数据库中的数据，为CSS属性添加必要的浏览器前缀，以确保样式兼容不同版本的浏览器
import autoprefixer from "autoprefixer";
// Tailwind CSS 是一个高度可定制的实用优先的 CSS 框架，可以直接在 HTML 元素上添加这些类，而无需在单独的 CSS 文件中编写大量的样式规则
import tailwindcss from "tailwindcss";
// cssnano插件提供了更多的css压缩优化功能
import cssnano from "cssnano";

const createConfig = (env: any) => {
  return {
    server: {
      host: "0.0.0.0",
      port: 5173,
      open: true,
      // 注意：ssl证书是针对特定域名颁发的，所以生产环境的ssl证书在本地 localhost 会失效，因为域名不匹配。
      // 如果想开发环境也配置有效的https，可以使用mkcert生成针对 localhost 域名的【证书颁发机构CA证书】和【ssl证书】，双击【证书颁发机构CA证书】进行安装将其配置成可信任的证书颁发机构，这样基于该机构生成的ssl证书也可信任了。
      https: {
        // 使用开发环境的ssl证书
        cert: fs.readFileSync(path.join(__dirname, "ssl/dev/cert.crt")),
        key: fs.readFileSync(path.join(__dirname, "ssl/dev/cert.key")),
        // 使用生产环境的ssl证书（仅用于测试“生产环境的ssl证书在本地 localhost 会失效”，生产环境的ssl证书需要去nginx配置）
        // cert: fs.readFileSync(path.join(__dirname, "ssl/prod/hoo6w6.us.kg.crt")),
        // key: fs.readFileSync(path.join(__dirname, "ssl/prod/hoo6w6.us.kg.pem")),
      },
      proxy: {
        // 匹配请求路径，并将请求转发到目标服务器
        "/novel": {
          // 目标服务器
          target: "https://localhost:3000",
          // 将请求头中的 host 配置为 target
          changeOrigin: true,
          // 是否代理websocket
          ws: true,
          // 是否验证 SSL 证书，请求是https协议时需要开启
          secure: false,
          // 将代理服务器的请求路径改写成目标服务器的请求路径
          rewrite: (path: string) => path.replace(new RegExp(`^${env.VITE_APP_BASE_URL}`), ""),
        },
      },
      cors: true, // 配置 CORS
    },
    plugins: [
      vue(),
      // 自动引入组件，打包的时候查看用到了哪个element-plus的组件就打包对应的组件代码。
      AutoImport({
        // 自动导入 Vue 相关函数，如：ref, reactive, toRef 等，也可以导入其他库的相关函数，这样在页面里就不再需要手动引入了
        imports: ["vue", "vue-router"],
        // 自动导入 Element Plus 相关函数，如：ElMessage, ElMessageBox... (带样式)
        resolvers: [
          // 自动导入 Element Plus 的 组件
          ElementPlusResolver({
            // 自动引入修改主题色添加这一行，使用预处理样式
            // 不添加将会导致使用ElMessage，ElNotification等组件时默认的主题色会覆盖自定义的主题色
            importStyle: "sass",
          }),
        ],
        // 指定声明文件生成路径，检测到项目使用ts时，如果没有指定路径，它会默认生成类型声明文件在根目录（即默认路径为 ./auto-imports.d.ts）
        dts: "src/types/unplugin/auto-imports.d.ts",
        // 解决eslint报错问题
        eslintrc: {
          // 这里enabled先设置成true，然后 npm run dev 运行之后会生成 .eslintrc-auto-import.json 文件，之后，再改为false
          enabled: true,
          filepath: "./.eslintrc-auto-import.json", // 生成的文件路径
          globalsPropValue: true,
        },
      }),
      // 自动注册组件
      Components({
        dirs: ["src/components"], // 默认导入该目录的所有组件作为全局组件，免去import的麻烦
        resolvers: [
          // 自动注册 Element Plus 组件
          ElementPlusResolver({
            // 按需引入修改主题色添加这一行，使用预处理样式
            importStyle: "sass",
          }),
        ],
        // 指定声明文件的生成路径。检测到项目使用ts时，如果没有指定路径，它会默认生成类型声明文件在根目录（即默认路径为 ./components.d.ts）
        dts: "src/types/unplugin/components.d.ts",
      }),
      // 组件库样式自动按需导入
      createStyleImportPlugin({
        resolves: [ElementPlusResolve()],
        libs: [
          // 如果没有你需要的resolve，可以在lib内直接写，也可以给我们提供PR
          {
            libraryName: "element-plus",
            esModule: true,
            resolveStyle: (name) => {
              return `element-plus/lib/theme-chalk/${name}.css`;
            },
            ensureStyleFile: true, // 忽略文件是否存在, 导入不存在的CSS文件时防止错误。
          },
        ],
      }),
      // 解决使用script setup后无法自定义vue组件名的问题
      VitePluginVueSetupExtend(),
      // 使用算法对代码进行压缩
      ViteCompression({
        verbose: true, // 是否在控制台输出压缩结果
        disable: false, // 是否禁用
        threshold: 10240, // 文件容量大于这个值进行压缩，它将被压缩，单位为b
        algorithm: "gzip", // 压缩算法 可选 ['gzip','brotliCompress' ,'deflate','deflateRaw']
        ext: ".gz", // 生成的压缩包后缀
      }),
    ],
    css: {
      preprocessorOptions: {
        scss: {
          // 去除启动项目时sass报的legacy-js-api过期警告
          // quietDeps: true, // 可以尝试，但在高版本中似乎不起作用
          silenceDeprecations: ["legacy-js-api"],
        },
      },
      /**
       * vite内置了postcss，不需要再安装postcss
       * postcss可以配置在项目根目录的postcss.config.js文件里，也可以配置在css这里面。
       * PostCSS 可以将未来的 CSS 语法转换为当前浏览器能够理解的语法。
       * PostCSS 可以使用如 autoprefixer 这样的 PostCSS 插件，为 CSS 代码自动添加浏览器厂商前缀。
       */
      postcss: {
        // 关键代码
        plugins: [
          // autoprefixer插件为CSS属性添加必要的浏览器前缀，以确保样式兼容不同版本的浏览器
          autoprefixer({
            // 指定兼容浏览器版本的范围，Autoprefixer 会自动为这些浏览器需要的 CSS 属性添加前缀。
            overrideBrowserslist: [
              "Android 4.1",
              "iOS 7.1",
              "Chrome > 31",
              "> 1%",
              "last 2 versions", // 所有主流浏览器最近2个版本
              "not ie <= 11",
            ],
            grid: false, // 是否为 Grid 布局添加相应的浏览器前缀
          }),
          /**
           * 安装tailwindcss作为postcss的插件
           * TailwindCSS与PostCSS的结合：
           * TailwindCSS本身是基于PostCSS构建的，这意味着你可以利用PostCSS的丰富插件生态系统来进一步增强TailwindCSS的功能。
           */
          tailwindcss(),
          /**
           * cssnano【nano是毫微，即非常小的意思，nanometer是毫微米，也叫纳米】 是一个 PostCSS 插件，可以添加到你的构建流程中，用于确保最终生成的 用于生产环境的 CSS 样式表文件尽可能的小。
           * cssnano插件要放在后面，先经过前面的autoprefixer插件自动添加前缀处理，cssnano插件再进行优化。
           * esbuild已经给vite提供了压缩css的功能，为什么还要用cssnano？
           * 因为除了基本的css压缩功能之外，cssnano拥有比esbuild更多的css压缩优化功能（如：将多个不同类名的相同样式提取出去放在一起；将rgba颜色转成十六进制的哈希值颜色；给样式按字母排序等），这样能把css压缩得更小。
           *
           * esbuild压缩和cssnano压缩对比【这里对比LargeFileSegmentUpload.css文件压缩后的字节数】：
           * esbuild压缩：          18,379 字节
           * cssnano的default压缩： 18,160 字节
           * cssnano的advanced压缩：14,202 字节
           */
          cssnano({
            /**
             * 预设可选值：default | advanced | lite
             * default：默认，有些css优化不支持
             * advanced：进阶，高级转换，支持比default更多的css优化，需要安装依赖 npm install -D cssnano-preset-advanced
             * lite：轻量，支持很少的css优化，很多优化都不支持，基本用不到，需要安装依赖 npm install -D cssnano-preset-lite
             */
            preset: "advanced",
          }),
        ],
      },
    },
    resolve: {
      alias: {
        "@": fileURLToPath(new URL("./src", import.meta.url)),
      },
    },
  };
};

// https://vitejs.dev/config/
export default defineConfig(createConfig);
